#include "RpcWebClient.h"
#include "SE_Exception.h"


//public
RpcWebClient::RpcWebClient() :
    RpcClient(),
    m_connType(eConnTypeView),
    m_connId(eConnIdInvalid),
    m_fIsAuthenticated(false),
    m_fIsSvcProtected(false),
    m_code("")
{ }

//public
RpcWebClient::RpcWebClient(__in std::string &svcAddress, __in std::string &svcEndpoint, __in tag_eConnType connType) :
    RpcClient(svcAddress, svcEndpoint),
    m_connType(connType),
    m_connId(eConnIdInvalid),
    m_fIsAuthenticated(false),
    m_fIsSvcProtected(false),
    m_code("")
{
    if (!(m_connType == eConnTypeDraw || m_connType == eConnTypeView)) {

        m_connType = eConnTypeView;
    }
}

//public    
RpcWebClient::~RpcWebClient() {

    if (InqIsConnected()) {

        Disconnect();
    }

    if (InqIsBound()) {

        _Unbind();
    }

    m_fIsAuthenticated = false;

    m_fIsSvcProtected = false;

    m_code.clear();
}

//public
// virtual RpcClient::Connect
bool RpcWebClient::Connect() {

    RPC_STATUS  status      = S_OK;
    bool        fConnected  = false;
    byte        name[0x100] = { 0 };


    // Create binding
    if (!_Bind()) {

        return false;
    }

    // Create client connection instance on server-side
    try {

        sub_4017C0(m_hBinding, m_connType, name, &m_connId);

        if (eConnIdInvalid == m_connId ) {

            _SetErrCode(ERROR_NOT_CONNECTED);

            _SetErrInfo(__FUNCTION__ " : bw_connect falied.");

            fConnected = false;
        }
        else {

            fConnected = true;
        }
    }
    catch(SE_Exception e) {

        _SetErrCode( e.InqSE() );

        _SetErrInfo(__FUNCTION__ " : bw_connect faulted with exception.");

        fConnected = false;
    }

    if (!fConnected) {

        _Unbind();

        return false;
    }

    if (!_ConnectionProbe()) {

        try {

            sub_401AD0(m_hBinding, m_connId, true);

            m_connId = eConnIdInvalid;
        }
        catch(SE_Exception e) {

            _SetErrCode(e.InqSE());

            _SetErrInfo(__FUNCTION__ " : bw_disconnect faulted with exception.");
        }

        _Unbind();

        return false;
    }

    _SetIsConnected(true);

    _ConnectionPost();

    return true;
}

//public
// virtual RpcClient::Disconnect
void RpcWebClient::Disconnect() {

    if (InqIsConnected()) {

        try {

            sub_401AD0(m_hBinding, m_connId, true);
        }
        catch(SE_Exception e) {

            _SetErrCode( e.InqSE() );

            _SetErrInfo(__FUNCTION__ " : bw_disconnect faulted with exception.");
        }
    }


    _SetIsConnected( false );

    m_connId = eConnIdInvalid;
    
    m_fIsAuthenticated = false;

    m_fIsSvcProtected = false;

    m_code.clear();

    _Unbind();

    return;
}

//public    
bool RpcWebClient::Configure(__in std::string &svcAddress, __in std::string &svcEndpoint, __in tag_eConnType connType) {

    if (!InqIsBound()) {

        m_strSvcAddress = svcAddress;

        m_strSvcEndpoint = svcEndpoint;
    }
    else {

        return false;
    }

    if (!InqIsConnected()) {

        m_connType = connType;

    } else {

        return false;
    }

    return true;
}

//public    
bool RpcWebClient::ExecuteRequest(__in long ioctl, __in long sizeIn, __in byte *buffIn, __in long sizeOut, __out byte *buffOut, __out long *pResultOut) {

    bool    fResult = false;


    *pResultOut = 0;

    if (!InqIsBound()) {

        return false;
    }

    try {
        
        sub_401000(m_hBinding, m_connId, ioctl, sizeIn, buffIn, sizeOut, buffOut, pResultOut);

        fResult = true;
    }
    catch(SE_Exception e) {

        _SetErrCode( e.InqSE() );

        _SetErrInfo( __FUNCTION__ " bw_io: faulted with exception.");

        fResult = false;
    }

    return fResult;
}

//protected virtual RpcClient::_ConnectionProbe()
bool RpcWebClient::_ConnectionProbe() {

    return true;
}

//protected virtual PpcClient::_ConnectionPost
#pragma pack(push, 1)
void RpcWebClient::_ConnectionPost() {
    
    struct {
        byte    str_000_020[0x20];
    } tagCmdIn = { 0 };

    struct {
        byte    str_000_020[0x20];
    } tagCmdOut = { 0 };

    struct {
        unsigned    u32_000_004;
    } tagCmdIn2  = { 0 };

    struct {
        char    str_000_020[0x20];
    } tagCmdOut2  = { 0 };

    long    status = 0;


    if (!(InqIsBound() && InqIsConnected())) {

        return;
    }

    if (!ExecuteRequest(51001, sizeof(tagCmdIn), (byte*)&tagCmdIn, sizeof(tagCmdOut), (byte*)&tagCmdOut, &status)) {

        return;
    }
    else {

        m_fIsAuthenticated = true;
    }

    if (!ExecuteRequest(50003, sizeof(tagCmdIn2), (byte*)&tagCmdIn2, sizeof(tagCmdOut2), (byte*)&tagCmdOut2, &status)) {

        return;
    }
    else {
    
        tagCmdOut2.str_000_020[sizeof(tagCmdOut2) -1] = '\0';

        m_code = tagCmdOut2.str_000_020;

        m_fIsSvcProtected = (tagCmdOut2.str_000_020[0] != 0);
    }

    return;
}
#pragma pack(pop)

// public
bool RpcWebClient::InqIsAuthenticated() {

    return m_fIsAuthenticated;
}

// public
bool RpcWebClient::InqIsSvcProtected() {

    return m_fIsSvcProtected;
}
    
// public
void RpcWebClient::InqCode(__out std::string &codeOut) {

    codeOut = m_code;
}